#include "mboard.h"
#include "mboard_private.h"
#include "rcc.h"
#include "nvic.h"
#include "dma_hw.h"
#include "mdebug.h"

/**
 * DMA2 -- 数据流7 -- 通道4 -- USART1_TX
 * DMA2 -- 数据流5 -- 通道4 -- USART1_RX
 */

typedef struct {
	
} MDmaInfo_t;

static void mDmaClockInit(void)
{
	/* 使能DMA2时钟 */
	RCC_EnableAhb1(RCC_CLK_AHB1_DMA2);
}

static void mDmaInterruptInit(void)
{
	NVIC_SetPriority(NVIC_IRQ_DMA2_STREAM5, NVIC_PRIORITY_LOW,
	                 NVIC_PRIORITY_SUB_NONE);
	NVIC_EnableIrq(NVIC_IRQ_DMA2_STREAM5);
	NVIC_SetPriority(NVIC_IRQ_DMA2_STREAM7, NVIC_PRIORITY_LOW,
	                 NVIC_PRIORITY_SUB_NONE);
	NVIC_EnableIrq(NVIC_IRQ_DMA2_STREAM7);
}

void mDmaInit(void)
{
	mDmaClockInit();
	mDmaInterruptInit();
}

static uint32_t bufSrc[10];
static uint32_t bufDst[10];

void mDmaTest(void)
{
	uint32_t i;
	uint32_t count;

	/* 测试10次 */
	count = 10;

START:
	/* 初始化两个数组 */
	for (i = 0; i < sizeof(bufSrc)/4; i++) {
		bufSrc[i] = i;
		bufDst[i] = 0;
	}

	/* 等待DMA空闲，只有DMA2支持存储到存储的搬运 */
	while (_DMA_IsBusy(SOC_DMA2_S7));
	/* 配置DMA */
	SOC_DMA2_S7.CR = DMA_CR_DIS |           // 停止传输
	                 DMA_CR_DMEIE_EN |      // 使能直接模式错误中断
	                 DMA_CR_TEIE_EN |       // 使能传输错误中断
	                 DMA_CR_HTIE_DIS |      // 禁止半完成中断
	                 DMA_CR_TCIE_DIS |      // 禁止传输完成中断
	                 DMA_CR_PFCTRL_DMA |    // 由DMA控制传输完成，存储到存储
					                        // 必须选择该模式
	                 DMA_CR_DIR_M2M |       // 存储到存储
	                 DMA_CR_CIRC_DIS |      // 禁止循环式，存储到存储不支持
	                 DMA_CR_PINC_EN |       // 源地址递增
	                 DMA_CR_MINC_EN |       // 目的地址递增
	                 DMA_CR_PSIZE_1 |       // 源地址加1，PINC_DIS时无关
	                 DMA_CR_MSIZE_1 |       // 目的地址加1
                     DMA_CR_PINCOS_DIS |    // 外设递增由PSIZE决定，PINC=0时
	                 DMA_CR_PL_LOW |        // 最低优先级
	                 DMA_CR_DBM_DIS |       // 禁用双缓冲区模式，存储到存
					                        // 储不支持
	                 DMA_CR_CT_M0 |         // 当前使用M0AR寻址
	                 DMA_CR_PBURST_INCR4 |  // 突发传输，4节拍
	                 DMA_CR_MBURST_INCR4 |  // 突发传输，4节拍
	                 DMA_CR_CHSEL_0;        // 选择通道0，存储到存储时通道无关
	/* 配置DMA FIFO */
	SOC_DMA2_S7.FCR = DMA_FCR_FTH_4 |       // 1/4容量
	                  DMA_FCR_DMDIS_DIS |   // 使能FIFO模式，存储到存储必
					                        // 须使用FIFO
	                  DMA_FCR_FEIE_EN;      // 启用FIFO错误中断
	/* 源地址 */
	SOC_DMA2_S7.PAR  = DMA_PAR_0_FFFFFFFFH(&bufSrc);
	/* 目的地址 */
	SOC_DMA2_S7.M0AR = DMA_M0AR_0_FFFFFFFFH(&bufDst);
	/* 以PSIZE为项目单位，此处项目数等于字节数 */
	SOC_DMA2_S7.NDTR = DMA_NDTR_0_65535D(sizeof(bufSrc));
	/* 清除所有状态标志 */
	SOC_DMA2.IFCR[DMA_IDX_4_7D(7)] = DMA_S7_FLAG(DMA_FLAG_ALL);

	/* 启动传输 */
	SOC_DMA2_S7.CR |= DMA_CR_EN;
	/* 等待传输完成 */
	while (_DMA_IsBusy(SOC_DMA2_S7));

	/* 对比两个数组 */
	for (i = 0; i < sizeof(bufSrc)/4; i++) {
		if ((bufSrc[i] != bufDst[i]) && (bufDst[i] != i)) {
			mDebugPutMemoryForU8("Dst: ", (uint8_t *)bufDst, sizeof(bufDst));
			mDebugPutMemoryForU8("Src: ", (uint8_t *)bufSrc, sizeof(bufSrc));
		}
	}

	if (count--) {
		goto START;
	}

	mDebugPuts("DMA Test Succeed");
}
